Ext.define('commons.ux.TreePickerEx', {
    extend: 'Ext.form.field.Picker',
    alias: 'widget.treepickerux',
    uses: [
        'Ext.tree.Panel'
    ],
    triggerCls: Ext.baseCSSPrefix + 'form-arrow-trigger',
    config: {
        /**
         * @cfg {Ext.data.TreeStore} store
         * A tree store that the tree picker will be bound to
         */
        store: null,
        /**
         * @cfg {String} displayField
         * The field inside the model that will be used as the node's text.
         * Defaults to the default value of {@link Ext.tree.Panel}'s `displayField` configuration.
         */
        displayField: null,
        /**
         * @cfg {Array} columns
         * An optional array of columns for multi-column trees
         */
        columns: null,
        /**
         * @cfg {Boolean} selectOnTab
         * Whether the Tab key should select the currently highlighted item. Defaults to `true`.
         */
        selectOnTab: true,
        /**
         * @cfg {Number} maxPickerHeight
         * The maximum height of the tree dropdown. Defaults to 300.
         */
        maxPickerHeight: 300,
        /**
         * @cfg {Number} minPickerHeight
         * The minimum height of the tree dropdown. Defaults to 100.
         */
        minPickerHeight: 100,
        
        rootVisible : false,
        
        checkPropagation : 'none'
    },
    editable: false,
    /**
     * @event select
     * Fires when a tree node is selected
     * @param {Ext.ux.TreePicker} picker        This tree picker
     * @param {Ext.data.Model} record           The selected record
     */
    initComponent: function () {
        var me = this;
        me.callParent(arguments);
        me.mon(me.store, {
            scope: me,
            load: me.onLoad,
            update: me.onUpdate
        });
    },
    /**
     * Creates and returns the tree panel to be used as this field's picker.
     */
    createPicker : function() {
		var me = this, picker = new Ext.tree.Panel({
			baseCls : Ext.baseCSSPrefix + 'boundlist',
			shrinkWrapDock : 2,
			checkPropagation : me.checkPropagation,
			store : me.store,
			floating : true,
			rootVisible : me.rootVisible,
			displayField : me.displayField,
			columns : me.columns,
			minHeight : me.minPickerHeight,
			maxHeight : me.maxPickerHeight,
			manageHeight : false,
			shadow : false,
			selModel : new Ext.selection.TreeModel({
				mode : me.multiSelect ? 'MULTI' : 'SINGLE'
			}),
			tbar : [ {
				xtype : 'button',
				text : '确定',
				handler : function() {
					me.submit.call(me);
					var data;
					if (me.checkboxSelect)
						data = picker.getChecked();
					else
						data = picker.getSelection();
					me.fireEvent('submit', data);
				}
			}, {
				xtype : 'button',
				text : '清空',
				handler : function() {
					var data = picker.getChecked();
					Ext.each(data, function(d) {
						d.set('checked', false);
					});
					me.value = [];
					me.setRawValue('');
					me.fireEvent('clear');
				}
			}, {
				xtype : 'button',
				text : '关闭',
				handler : function() {
					me.collapse();
				}
			} ],
			listeners : {
				scope : me,
				itemclick : me.onItemClick,
				itemkeydown : me.onPickerKeyDown
			// beforehide : function() {return false;}
			}
		}), view = picker.getView();
		if (Ext.isIE9 && Ext.isStrict) {
			// In IE9 strict mode, the tree view grows by the
			// height of the horizontal scroll bar when the
			// items are highlighted or unhighlighted.
			// Also when items are collapsed or expanded the
			// height of the view is off. Forcing a repaint
			// fixes the problem.
			view.on({
				scope : me,
				highlightitem : me.repaintPickerView,
				unhighlightitem : me.repaintPickerView,
				afteritemexpand : me.repaintPickerView,
				afteritemcollapse : me.repaintPickerView
			});
		}
		this.picker = picker;
		picker.on('checkchange', function(node, checked, e, eOpts)  {
			// 选中节点  那么它所有的父节点也要递归被选中
			if (checked) {
				me.recursiveParentNode(node);
			}
		})
		return picker;
	},
    submit: function () {
        var tree = this.picker || this.getPicker();
        var rootNode = this.store.getRoot();
        var data;
        if (this.checkboxSelect)
            data = tree.getChecked();
        else
            data = tree.getSelection();
        if (data && data.length) {
            var ids = [], rawValueArr = [];
            loop : for (var i = 0; i < data.length; i++) {
                var record = data[i];
                if (record.id == '0') continue; // 排除 root='0'节点
                ids.push(record.id);
                var rawValue = '';
                if (this.valueDisplayField) {
                    rawValue = record.get(this.valueDisplayField);
                    if (!rawValue && record.data.attachment)
                        rawValue = record.data.attachment[this.valueDisplayField];
                } else {
                    rawValue = record.get(this.valueDisplayField || 'text')//record.getPath('text').replace('/' + rootNode.get('text'), '');
                    if (!rawValue) // root节点
                        rawValue = '/';
                }
                rawValueArr.push(rawValue);
            }
            this.value = ids;
            this.setRawValue(rawValueArr.join(','));
        }
        this.collapse();
    },
    setValue: function (setVals) {

    		// me.values是储存在内部的值，用于getValue时返回。
        // me.setRawValue只是用于展示UI。
        var me = this, record;
        // if (typeof values == 'string') {
        //     values = [values];
        // }
        // if (values.length) { //尽量不用这里的逻辑
        //     me.value = values;
        //     if (me.store.loading) {
        //         return me;
        //     }
        //     var paths = [];
        //     var rootNode = me.store.getRoot();
        //     for (var i = 0; i < values.length; i++) {
        //         var value = values[i];
        //         record = value ? me.store.getNodeById(value) : me.store.getRoot();
        //         if (this.checkboxSelect)
        //             record.set('checked', true);
        //         //me.picker.getSelectionModel().select(record);
        //         var path = record.getPath('text').replace('/' + rootNode.get('text'), '');
        //         if (!path) // root节点
        //             path = '/';
        //         paths.push(path);
        //     }
        //     me.setRawValue(paths.join(','));
        //}
        me.value = [], paths = [];
        if (setVals && !setVals.length) {
            setVals = [setVals];
        }
        if (setVals) {
            for (var i = 0; i < setVals.length; i++) {
                var d = setVals[i];
                me.value.push(d.id)
                var f = this.valueDisplayField ? this.valueDisplayField : 'text';
                if (this.checkboxSelect) {
                    var record = me.store.getNodeById(d.id);
                    if (record) {
                    		record.set('checked', true);
                    		paths.push(record.get(f));
                    }
                }
            }
        }
        me.setRawValue(paths.join(','));
        return me;
    },
    setValueEx: function (node) {
        var me = this, record;
        if (node) {
            var path = '';
            if (node.path)
                path = node.path;
            else if (node.getPath) {
                path = node.getPath('text').replace('/root', '').replace('/Root', '') + '/';
            }
            node = {
                id: node.id,
                path: path
            }
            this.setValue(node);
        }
        return me;
    },
    /**
     * repaints the tree view
     */
    repaintPickerView: function () {
        var style = this.picker.getView().getEl().dom.style;
        // can't use Element.repaint because it contains a setTimeout, which results in a flicker effect
        style.display = style.display;
    },
    /**
     * Handles a click even on a tree node
     * @private
     * @param {Ext.tree.View} view
     * @param {Ext.data.Model} record
     * @param {HTMLElement} node
     * @param {Number} rowIndex
     * @param {Ext.event.Event} e
     */
    onItemClick: function (view, record, item, rowIndex, e) {
    		var self = this;
        this.selectItem(record);
        if (this.checkboxSelect) {
            var node = this.picker.store.getNodeById(record.id);
            var checked = node.get('checked');
            self.recursiveChildNode(node, checked);
        }
    },
    
    recursiveChildNode : function(node, checked) {
    		var self = this;
    		if (node && node.childNodes && node.childNodes.length && this.selectCascade) {
    			Ext.each(node.childNodes, function (n) {
                n.set('checked', checked);
                self.recursiveChildNode(n, checked);
            })
    		}
    },

    recursiveParentNode : function(node) {
		var self = this;
		if (node.parentNode && this.selectCascade && !node.parentNode.isRoot()) {
			node.parentNode.set('checked', true);
			self.recursiveParentNode(node.parentNode);
		}
	},
    /**
     * Handles a keypress event on the picker element
     * @private
     * @param {Ext.event.Event} e
     * @param {HTMLElement} el
     */
    onPickerKeyDown: function (treeView, record, item, index, e) {
        var key = e.getKey();
        if (key === e.ENTER || (key === e.TAB && this.selectOnTab)) {
            this.selectItem(record);
        }
    },
    /**
     * Changes the selection to a given record and closes the picker
     * @private
     * @param {Ext.data.Model} record
     */
    selectItem: function (record) {
        var me = this;
        //me.setValue(record.getId());
        //me.fireEvent('select', me, record);
        //me.collapse();
        if (record.get('checked') && this.checkboxSelect && !this.multiSelect) {
            var records = this.picker.getStore().getRange();
            for (var i = 0; i < records.length; i++) {
                if (records[i].id != record.id) {
                    records[i].set('checked', false);
                }
            }
        }
    },
    /**
     * Runs when the picker is expanded.  Selects the appropriate tree node based on the value of the input element,
     * and focuses the picker so that keyboard navigation will work.
     * @private
     */
    onExpand: function () {
        var picker = this.picker,
            store = picker.store,
            value = this.value,
            node;
        if (value) {
            node = store.getNodeById(value);
        }
        if (!node) {
            node = store.getRoot();
        }
        picker.ensureVisible(node, {
            select: true,
            focus: true
        });
    },
    /**
     * Sets the specified value into the field
     * @param {Mixed} value
     * @return {Ext.ux.TreePicker} this
     */
    setValue0: function (value) {
        var me = this,
            record;
        me.value = value;
        if (me.store.loading) {
            // Called while the Store is loading. Ensure it is processed by the onLoad method.
            return me;
        }
        // try to find a record in the store that matches the value
        record = value ? me.store.getNodeById(value) : me.store.getRoot();
        if (value === undefined) {
            record = me.store.getRoot();
            me.value = record.getId();
        } else {
            record = me.store.getNodeById(value);
        }
        // set the raw value to the record's display field if a record was found
        me.setRawValue(record ? record.get(me.displayField) : '');
        return me;
    },
    getSubmitValue: function () {
        return this.value;
    },
    /**
     * Returns the current data value of the field (the idProperty of the record)
     * @return {Number}
     */
    getValue: function () {
        if (this.value && this.value.length && this.value.length == 1)
            this.value = this.value[0];
        var r = this.value ? this.value : null;
        if (r && this.valueTransform)
            return this.valueTransform.call(this, r);
        return r;
    },
    getSelectedNodes : function() {
				var tree = this.picker;
				var data = [];
				if (tree) {
					if (this.checkboxSelect)
						data = tree.getChecked();
					else
						data = tree.getSelection();
				}
				return data; 
	},
    /**
	 * Handles the store's load event.
	 * 
	 * @private
	 */
    onLoad: function () {
        // var value = this.value;
        // if (value) {
        //     this.setValue(value);
        // }
    },
    onUpdate: function (store, rec, type, modifiedFieldNames) {
        var display = this.displayField;
        if (type === 'edit' && modifiedFieldNames && Ext.Array.contains(modifiedFieldNames, display) && this.value === rec.getId()) {
            this.setRawValue(rec.get(display));
        }
    },
    reset: function () {
        this.value = [];
        this.setRawValue('');
        var _data = this.store.getData();
        if (_data && _data.length && this.checkboxSelect) {
            Ext.each(_data.items, function (r) {
                r.set('checked', false);
            })
        }
    }
});